#include "serverdev.h"
#include <QApplication>

#include <snmp_dev.h>
#include <snmp_pp/snmp_pp.h>
#include <snmp_pp/oid.h>
//#include <winsock2.h>
#include <QDebug>

using namespace  std;
using namespace  Snmp_pp;

//1.交换设备基本信息
//(1)设备状态信息
#define SYSDESCR          "1.3.6.1.2.1.1.1.0" //设备描述（只读）
#define SYSUPTIME         "1.3.6.1.2.1.1.3.0" //设备运行时间（只读）
#define SYSNAME           "1.3.6.1.2.1.1.5.0" //设备名称（只读）
#define PRODUCTDATE       "1.3.6.1.4.1.589.1.2.1" //出厂时间（只读）
#define SERIALNUMBER      "1.3.6.1.4.1.589.1.2.2" //出厂编号（只读）
#define SNMPSOFTVERSION   "1.3.6.1.4.1.589.1.2.3" //协议版本（交换机端版本）
#define PRODUCTNAME       "1.3.6.1.4.1.589.1.2.9.1" //产品名称（只读）
#define PRODUCTMANUFTURE  "1.3.6.1.4.1.589.1.2.9.2" //生产厂家（只读）
#define CPUUTILIZATION    "1.3.6.1.4.1.589.1.2.9.3" //CPU利用率（只读）
#define MEMORYUTILIZATION "1.3.6.1.4.1.589.1.2.9.4" //内存利用率（只读）
#define HERTBEAT          "1.3.6.1.4.1.589.1.2.9.5" //CPU心跳（只读）
#define SELFCHECK         "1.3.6.1.4.1.589.1.2.9.6" //自检（只读）
#define TEMPID            "1.3.6.1.4.1.589.1.2.9.8.1" //传感器ID（只读）
#define TEMPERATURE       "1.3.6.1.4.1.589.1.2.9.8.2" //温度值（只读）
//(2)端口状态新信息
#define IFINDEX1             "1.3.6.1.4.1.589.1.2.3.1" //端口索引（只读）
#define AGENTPORTDEFAULTTYPE "1.3.6.1.4.1.589.1.2.3.2" //设置端口速率双工（读写）
#define AGENTPORTTYPE        "1.3.6.1.4.1.589.1.2.3.3" //查询端口速率双工（只读）
#define AGENTPORTAUTO        "1.3.6.1.4.1.589.1.2.3.4" //端口自协商（读写）
#define PORTMODE             "1.3.6.1.4.1.589.1.2.3.5" //模式（读写）
//2.端口性能统计
#define IFINDEX2          "1.3.6.1.2.1.2.2.1" //接口索引（只读）
#define MTU               "1.3.6.1.2.1.2.2.2" //最大传输单元（只读）
#define IFSPEED           "1.3.6.1.2.1.2.2.3" //端口速率（只读）
#define IFADMINSTATUS1    "1.3.6.1.2.1.2.2.4" //端口管理状态（读写）
#define STATUS            "1.3.6.1.2.1.2.2.5" //接口状态（只读）
#define IFINALLBYTE       "1.3.6.1.2.1.2.2.6" //接收总字节（只读）
#define IFINSIGLEPACKAGE  "1.3.6.1.2.1.2.2.7" //接收单播报文数（只读）
#define IFINMUTIPACKAGE   "1.3.6.1.2.1.2.2.8" //接收非单播报文数（只读）
#define IFINDISCARDS      "1.3.6.1.2.1.2.2.9" //接收丢包数（只读）
#define IFINERRORPAK      "1.3.6.1.2.1.2.3.0" //接收错包数（只读）
#define IFOUTALLBYTE      "1.3.6.1.2.1.2.3.1" //发送总字节（只读）
#define IFOUTSIGLEPAK     "1.3.6.1.2.1.2.3.2" //发送单播报文数（只读）
#define IFOUTMUTIPAK      "1.3.6.1.2.1.2.3.3"  //发送非单播报文数（只读）
#define IFOUTDISCARDS     "1.3.6.1.2.1.2.3.4" //发送丢包数（只读）
#define IFOUTERRORPAK     "1.3.6.1.2.1.2.3.5"  //发送错包数（只读）
//3.端口启动&禁用
#define IFINDEX3         "1.3.6.1.2.1.2.5.3" //接口索引（只读）
#define IFADMINSTATUS2   "1.3.6.1.2.1.2.5.2" //端口管理状态（读写）
//4.设置配置
#define CONFIGSAVE     "1.3.6.1.4.1.589.1.6.1"  //配置保存（读写）
#define CONFIGRESET    "1.3.6.1.4.1.589.1.6.2"  //删除配置（读写）

#define _GET_     0
#define _GETBULK_ 0
#define _SET_     0
// determine the smi type and get a value from the user
bool determine_vb(SmiUINT32 val, Vb &vb)
{
    char buffer[255];

    if (val == sNMP_SYNTAX_NOSUCHINSTANCE)
    {
        std::cout << "Instance does not exists but can be created.\n";
        std::cout << "Please enter one of the following types:\n\n";
        std::cout << "Integer:  " << sNMP_SYNTAX_INT << "\n";
        std::cout << "Bits:     " << sNMP_SYNTAX_BITS << "\n";
        std::cout << "STRING:   " << sNMP_SYNTAX_OCTETS << "\n";
        std::cout << "Oid:      " << sNMP_SYNTAX_OID << "\n";
        std::cout << "IpAddress:" << sNMP_SYNTAX_IPADDR << "\n\n";
        std::cout << "Please choose value type: ";
        std::cin >> val;
        vb.set_syntax(val);
    }
    std::cout << "Value Type is ";

    switch (val)
    {

    // octet string
    case sNMP_SYNTAX_OCTETS:
    {
        std::cout << "Octet String\n";
        std::cout << "Please enter new value: ";
       // std::cin >> buffer;
        OctetStr octetstr(buffer);
        if (octetstr.valid())
        {
            vb.set_value("666");
            return true;
        }
        else
        {
            std::cout << "Invalid OctetStr\n";
            return false;
        }
    }

        // IP Address
    case sNMP_SYNTAX_IPADDR:
    {
        std::cout << "IP Address\n";
        std::cout << "Please enter new value: ";
        std::cin >> buffer;
        IpAddress ipaddress(buffer);
        if (ipaddress.valid()) {
            vb.set_value(ipaddress);
            return true;
        }
        else {
            std::cout << "Invalid IP Address\n";
            return false;
        }
    }

        // Oid
    case sNMP_SYNTAX_OID:
    {
        std::cout << "Oid\n";
        std::cout << "Please enter new value: ";
        std::cin >> buffer;
        Oid oid(buffer);
        if (oid.valid()) {
            vb.set_value(oid);
            return true;
        }
        else {
            std::cout << "Invalid Oid\n";
            return false;
        }
    }

        // TimeTicks
    case sNMP_SYNTAX_TIMETICKS:
    {
        std::cout << "TimeTicks\n";
        std::cout << "Please enter new value: ";
        std::cin >> buffer;
        unsigned long i;
        i = atol(buffer);
        TimeTicks timeticks(i);
        if (timeticks.valid()) {
            vb.set_value(timeticks);
            return true;
        }
        else {
            std::cout << "Invalid TimeTicks\n";
            return false;
        }
    }

        // Gauge32
    case sNMP_SYNTAX_GAUGE32:
    {
        std::cout << "Gauge32\n";
        std::cout << "Please enter new value: ";
        std::cin >> buffer;
        unsigned long i;
        i = atol(buffer);
        Gauge32 gauge32(i);
        if (gauge32.valid()) {
            vb.set_value(gauge32);
            return true;
        }
        else {
            std::cout << "Invalid Gauge32\n";
            return false;
        }
    }

    case sNMP_SYNTAX_CNTR32:
    {
        std::cout << "Counter32\n";
        std::cout << "Please enter new value: ";
        std::cin >> buffer;
        unsigned long i;
        i = atol(buffer);
        Counter32 counter32(i);
        if (counter32.valid()) {
            vb.set_value(counter32);
            return true;
        }
        else {
            std::cout << "Invalid Counter32\n";
            return false;
        }
    }

    case sNMP_SYNTAX_CNTR64:
    {
        std::cout << "Counter64\n";
        std::cout << "Please enter value (low 32 bit): ";
        std::cin >> buffer;
        unsigned long i;
        i = atol(buffer);
        Counter64 counter64;
        counter64.set_low(i);

        std::cout << "Please enter value (high 32 bit): ";
        std::cin >> buffer;
        i = atol(buffer);
        counter64.set_high(i);

        if (counter64.valid()) {
            vb.set_value(counter64);
            return true;
        }
        else {
            std::cout << "Invalid Counter64\n";
            return false;
        }
    }

    case sNMP_SYNTAX_INT:
    {
        std::cout << "Integer\n";
        std::cout << "Please enter new value: ";
        std::cin >> buffer;
        unsigned long i;
        i = atol(buffer);
        long l ;
        l = (long) i;
        vb.set_value(l);
        return true;
    }

    case sNMP_SYNTAX_NOSUCHOBJECT:
    {
        std::cout << "NO SUCH OBJECT\n";
        std::cout << "Object cannot be created.\n";
        return false;
    }
    default:
        std::cout << "Unknown Data Type " << val << "\n";
        return false;
    }
}

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

#if _GET_
    Snmp::socket_startup();  //初始化socket子系统
    int status;
    Vb vb[3];
    Pdu pdu;
    vb[0].set_oid(SYSDESCR);
    vb[1].set_oid(SYSUPTIME);
    vb[2].set_oid(SYSNAME);
    pdu.set_vblist(vb,3);
    CTarget ctarget((IpAddress) "127.0.0.1");  //被管代理的ip
    Snmp snmp(status);
    if((status=snmp.get(pdu, ctarget))!=SNMP_CLASS_SUCCESS)
    {
        cout<<snmp.error_msg(status);

        qDebug() << snmp.error_msg(status);
    }
    else
    {
       pdu.get_vblist(vb,3);
       for(int i=0;i<pdu.get_vb_count();i++)
       {
           qDebug() << "oid:"<<vb[i].get_printable_oid()<<" "<<"value:"<<vb[i].get_printable_value()<<endl;
       }
    }
    Snmp::socket_cleanup();
#endif

#if _GETBULK_
    //getBulk操作
    Snmp::socket_startup();  // Initialize socket subsystem

    //---------[ make a GenAddress and Oid object to retrieve ]---------------
    UdpAddress address("127.0.0.1");      // make a SNMP++ Generic address
    if (!address.valid())
    {           // check validity of address
        std::cout << "Invalid Address or DNS Name, " << "\n";
        return 1;
    }

    Pdu pdu;                              // construct a Pdu object
    Vb vb;                                // construct a Vb object
    Oid oid("1.3.6.1.2.1.1.1.1");         // default is sysDescr
    vb.set_oid(oid);
    pdu += vb;                            // add the vb to the Pdu


    //---------[ determine options to use ]-----------------------------------
    snmp_version version=version2c;          // default is v2c
    int retries=1;                          // default retries is 1
    int timeout=100;                        // default is 1 second
    u_short port=161;                       // default snmp port is 161
    OctetStr community("public");           // community name
    int non_reps=0;                         // non repeaters default is 0
    int max_reps=35;                        // maximum repetitions default is 10

    //----------[ create a SNMP++ session ]-----------------------------------
    int status;
    // bind to any port and use IPv6 if needed
    Snmp snmp(status, 0, (address.get_ip_version() == Address::version_ipv6));

    if (status != SNMP_CLASS_SUCCESS)
    {
     std::cout << "SNMP++ Session Create Fail, " << snmp.error_msg(status) << "\n";
     return 1;
    }

    //--------[ build up SNMP++ object needed ]-------------------------------
    address.set_port(port);
    CTarget ctarget(address);             // make a target using the address

    ctarget.set_version(version);         // set the SNMP version SNMPV1 or V2
    ctarget.set_retry(retries);           // set the number of auto retries
    ctarget.set_timeout(timeout);         // set timeout
    ctarget.set_readcommunity(community); // set the read community name


    //-------[ issue the request, blocked mode ]-----------------------------
    std::cout << "SNMP++ GetBulk to " << " Retries=" << retries<< " Timeout=" << timeout * 10 << "ms"<< " Non Reptrs=" << non_reps<< " Max Reps=" << max_reps << std::endl;

    std::cout << " Community=" << community.get_printable() << std::endl << std::flush;

    SnmpTarget *target;
    target = &ctarget;

    if ((status = snmp.get_bulk(pdu,*target,non_reps,max_reps))== SNMP_CLASS_SUCCESS)
    {
      cout<<"-------------------------------------"<<endl;
    for (int z=0;z<pdu.get_vb_count();z++)
    {
      pdu.get_vb(vb,z);
      std::cout << "Oid = " << vb.get_printable_oid() << "\n";
      if (vb.get_syntax() != sNMP_SYNTAX_ENDOFMIBVIEW)
      {
        std::cout << "Value = " << vb.get_printable_value() << "\n\n";
      }
      else
      {
        std::cout << "End of MIB view.\n\n";
      }
    }
    cout<<"-------------------------------------"<<endl;
    }
    else
    {
       std::cout << "SNMP++ GetBulk Error, " << snmp.error_msg(status) << "\n";
    }
    Snmp::socket_cleanup();  // Shut down socket subsystem
#endif

#if _SET_
    Snmp::socket_startup();  // Initialize socket subsystem
    //---------[ make a GenAddress and Oid object to retrieve ]---------------
    UdpAddress address("127.0.0.1");      // make a SNMP++ Generic address
    if (!address.valid())
    {           // check validity of address
        std::cout << "Invalid Address or DNS Name, " << argv[1] << "\n";
    }
    Oid oid(SYSDESCR);      // default is sysName
    //---------[ determine options to use ]-----------------------------------
    snmp_version version=version1;                  // default is v1
    int retries=1;                                  // default retries is 1
    int timeout=100;                                // default is 1 second
    u_short port=161;                               // default snmp port is 161
    OctetStr community("public");                   // community name
    OctetStr get_community;
    get_community = community;
    //----------[ create a SNMP++ session ]-----------------------------------
    int status;
    // bind to any port and use IPv6 if needed
    Snmp snmp(status, 0, (address.get_ip_version() == Address::version_ipv6));

    if (status != SNMP_CLASS_SUCCESS)
    {
        std::cout << "SNMP++ Session Create Fail, " << snmp.error_msg(status) << "\n";
        return 1;
    }
    //--------[ build up SNMP++ object needed ]-------------------------------
    Pdu pdu;                               // construct a Pdu object
    Vb vb;                                 // construct a Vb object
    vb.set_oid(oid);                      // set the Oid portion of the Vb
    pdu += vb;                             // add the vb to the Pdu
    address.set_port(port);
    CTarget ctarget(address);             // make a target using the address
    ctarget.set_version(version);         // set the SNMP version SNMPV1 or V2
    ctarget.set_retry(retries);           // set the number of auto retries
    ctarget.set_timeout(timeout);         // set timeout
    ctarget.set_readcommunity(get_community); // set the read community name
    ctarget.set_writecommunity(community);// set the write community name
    //-------[ issue the request, blocked mode ]-----------------------------
    std::cout << "SNMP++ Set to " << " Retries=" << retries<< " Timeout=" << timeout * 10 <<"ms";
    std::cout << " SET-community=" << community.get_printable()<< " GET-community=" << get_community.get_printable() << std::endl << std::flush;
    SnmpTarget *target;
    target = &ctarget;
    // first get the variabel to determine its type
    if ((status = snmp.get(pdu,*target))== SNMP_CLASS_SUCCESS)
    {
         pdu.get_vb(vb,0);
         std::cout << "Oid = " << vb.get_printable_oid() <<" "<< "Current Value = " << vb.get_printable_value() << std::endl;

         if (determine_vb(vb.get_syntax(), vb))
         {
             // do the Set
             Pdu setpdu;

             vb.set_oid(oid);           // use the same oid as the inquire
             setpdu += vb;
             status = snmp.set(setpdu, *target);
             qDebug() << "Set Status = " << snmp.error_msg(status) << "\n";
         }
    }
    else
    {
      std::cout << "SNMP++ Set Error, " << snmp.error_msg(status) << "\n";
    }
    Snmp::socket_cleanup();  // Shut down socket subsystem
#endif

    ServerDev serverdev;
    serverdev.show();


    return a.exec();
}
